home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / ARexxTools / fpl70.lha / src / hash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-08  |  24.0 KB  |  895 lines

  1. /******************************************************************************
  2.  *                   FREXX PROGRAMMING LANGUAGE                  *
  3.  ******************************************************************************
  4.  
  5.  hash.c
  6.  
  7.  Functions for FPL hash tables and sorting!
  8.  
  9.  *****************************************************************************/
  10.  
  11. /************************************************************************
  12.  *                                                                      *
  13.  * fpl.library - A shared library interpreting script langauge.         *
  14.  * Copyright (C) 1992-1994 FrexxWare                                    *
  15.  * Author: Daniel Stenberg                                              *
  16.  *                                                                      *
  17.  * This program is free software; you may redistribute for non          *
  18.  * commercial purposes only. Commercial programs must have a written    *
  19.  * permission from the author to use FPL. FPL is *NOT* public domain!   *
  20.  * Any provided source code is only for reference and for assurance     *
  21.  * that users should be able to compile FPL on any operating system     *
  22.  * he/she wants to use it in!                                           *
  23.  *                                                                      *
  24.  * You may not change, resource, patch files or in any way reverse      *
  25.  * engineer anything in the FPL package.                                *
  26.  *                                                                      *
  27.  * This program is distributed in the hope that it will be useful,      *
  28.  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
  29.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                 *
  30.  *                                                                      *
  31.  * Daniel Stenberg                                                      *
  32.  * Ankdammsgatan 36, 4tr                                                *
  33.  * S-171 43 Solna                                                       *
  34.  * Sweden                                                               *
  35.  *                                                                      *
  36.  * FidoNet 2:201/328    email:dast@sth.frontec.se                       *
  37.  *                                                                      *
  38.  ************************************************************************/
  39.  
  40. #ifdef AMIGA
  41. #include <exec/types.h>
  42. #include <proto/exec.h>
  43. #include <dos.h>
  44. #endif
  45. #include "script.h"
  46. #include <limits.h>
  47.  
  48. #ifdef DEBUG
  49. #include <stdio.h>
  50. #endif
  51.  
  52. static ReturnCode  AddIdentifier(struct Data *, struct Identifier *);
  53. static ReturnCode INLINE InitHash(struct Data *);
  54. static unsigned long INLINE Gethash(char *);
  55. static void * INLINE Init(struct Data *, long ASM (*)(AREG(0) void *), unsigned long *);
  56. static ReturnCode  SetTags(struct Data *, unsigned long *);
  57. #ifdef HIJACK
  58. static ReturnCode INLINE Hijack(struct Data *, struct Identifier *);
  59. #endif
  60. /**********************************************************************
  61.  *
  62.  * int fplAddFunction();
  63.  *
  64.  * User frontend to AddIdentifier().
  65.  *
  66.  *****/
  67.  
  68.  
  69. ReturnCode PREFIX
  70.   fplAddFunction(AREG(0) struct Data *scr,      /* pointer to struct Data */
  71.          AREG(1) char *name,     /* name of function */
  72.          DREG(0) long ID,     /* function ID */
  73.          DREG(1) char rtrn,      /* return type */
  74.          AREG(2) char *format,   /* format string */
  75.          AREG(3) unsigned long *tags) /* taglist pointer */
  76. {
  77.   ReturnCode ret;
  78.   struct Identifier *ident;
  79.   if(!scr)
  80.     return(FPLERR_ILLEGAL_ANCHOR);
  81.  
  82.   ident=MALLOCA(sizeof(struct Identifier));
  83.   if(!ident)
  84.     return(FPLERR_OUT_OF_MEMORY);
  85.  
  86.   memset(&ident->data.external, 0, sizeof(struct ExternalFunction));
  87.   while(tags && *tags) {
  88.     switch(*tags++) {
  89.     case FPLTAG_USERDATA:
  90.       ident->data.external.data=(void *)*tags;
  91.       break;
  92.     case FPLTAG_FUNCTION:
  93.       ident->data.external.func=(long (*)(void *))*tags;
  94.       break;
  95.     }
  96.     tags++; /* next! */
  97.   }
  98.  
  99.   ident->name = name;
  100.   ident->data.external.ID = ID;
  101.   ident->data.external.ret = rtrn;
  102.   ident->data.external.format = format;
  103.   ident->flags = FPL_EXTERNAL_FUNCTION;
  104.   ident->file = NULL; /* everywhere! */
  105.   ident->func = NULL; /* everywhere! */
  106.   ident->level = 0;
  107.  
  108.   CALL(AddIdentifier(scr, ident));
  109.   return(FPL_OK);
  110. }
  111.  
  112. /**********************************************************************
  113.  *
  114.  * int fplDelFunction();
  115.  *
  116.  * User frontend to DelIdentifier().
  117.  *
  118.  ******/
  119.  
  120. ReturnCode PREFIX fplDelFunction(AREG(0) struct Data *scr,
  121.                  AREG(1) char *name)
  122. {
  123.   ReturnCode ret;
  124.   if(!scr)
  125.     return(FPLERR_ILLEGAL_ANCHOR);
  126.   CALL(DelIdentifier(scr, name, NULL));
  127.   return(FPL_OK);
  128. }
  129.  
  130.  
  131. /**********************************************************************
  132.  *
  133.  * int AddVar();
  134.  *
  135.  * Frontend to the AddIdentifier function.
  136.  *
  137.  * This routine adds a member to the linked list of local variable names.
  138.  * That list exists to enable easy and fast removal of local variables
  139.  * when leaving a block within which local variables has been declared!
  140.  *
  141.  * Make sure that the name member data is static as long we need this list
  142.  * cause this routine doesn't copy that name, simply points to it!
  143.  *
  144.  *****/
  145.  
  146.  
  147. ReturnCode 
  148. AddVar(struct Data *scr, /* pointer to struct Data */
  149.        struct Identifier *ident,/* identifier struct pointer */
  150.        struct Local **local)
  151. {
  152.   ReturnCode ret;
  153.   struct Local *temp;
  154.   if(ret=AddIdentifier(scr, ident))
  155.     ;
  156.   else {
  157.     GETMEM(temp, sizeof(struct Local));  
  158.     temp->next=*local;
  159.     temp->ident=ident;
  160.     *local=temp;
  161.   }
  162.   return(ret);
  163. }
  164.  
  165. /**********************************************************************
  166.  *
  167.  * AddLevel();
  168.  *
  169.  * This function adds a NULL-name in the local symbol list to visualize
  170.  * the beginning of a new variable level!
  171.  *
  172.  *******/
  173.  
  174. ReturnCode  AddLevel(struct Data *scr)
  175. {
  176.   struct Local *temp;
  177.   GETMEM(temp, sizeof(struct Local));  
  178.   temp->next=scr->locals;
  179.   temp->ident=NULL;
  180.   scr->locals=temp;
  181.   return(FPL_OK);
  182. }
  183.  
  184.  
  185. /**********************************************************************
  186.  *
  187.  * int DelLocalVar()
  188.  *
  189.  * This routine deletes all members to the linked list of local variable
  190.  * names. Call this routine every time you leave a local level. Deletes
  191.  * all variables and the following NULL name!
  192.  *
  193.  *****/
  194.  
  195. ReturnCode 
  196. DelLocalVar(struct Data *scr,
  197.             struct Local **local)
  198. {
  199.   /* This removes only all listed symbols! */
  200.   struct Identifier *ident;
  201.   while(*local) {
  202.     struct Local *temp=(*local)->next;
  203.     ident=(*local)->ident;
  204.     FREE(*local);
  205.     *local=temp;
  206.     if(ident)
  207.       DelIdentifier(scr, NULL, ident); /* delete it for real */
  208.     else
  209.       break;
  210.   }
  211.   return(FPL_OK);
  212. }
  213.  
  214.  
  215. /**********************************************************************
  216.  *
  217.  * int AddIdentifier()
  218.  *
  219.  * This function adds the function to the hash table according to all
  220.  * parameters.
  221.  *
  222.  * If the hash member of the Data structure is NULL, the hash table
  223.  * will be inited. No not init the hash list if you don't have to cause
  224.  * that sure is a peep hole in the performance...
  225.  *
  226.  *******/
  227.  
  228. static ReturnCode 
  229. AddIdentifier(struct Data *scr,
  230.               struct Identifier *ident)
  231. {
  232.   unsigned long hash;       /* hash number of the identifier */
  233.   struct Identifier **add;  /* where to store the pointer to this identifier */
  234.   struct Identifier *prev=NULL; /* pointer to previous hash structure */
  235.   struct Identifier *next;  /* pointer to next hash structure */
  236.   ReturnCode ret;
  237.   hash=Gethash(ident->name);
  238.   
  239.   add=(struct Identifier **)&scr->hash[hash % scr->hash_size];
  240.   while(*add) {
  241.     if((*add)->hash==hash) {
  242.       /* they were identical */
  243.       if(ident->flags&FPL_FUNCTION &&
  244.      !strcmp((*add)->name, ident->name) &&
  245.      (!ident->file || !strcmp(ident->file, (*add)->file))) {
  246.     /* if it's a function, warning!!! */
  247.     CALL(Warn(scr, FPLERR_IDENTIFIER_USED));
  248.     DelIdentifier(scr, NULL, *add); /* remove it! */
  249.     /* we must call this routine again to re-read the lists with
  250.        the function removed! */
  251.     ret=AddIdentifier(scr, ident);
  252.     return(ret);
  253.       } else
  254.     /* add it here! */
  255.     break; 
  256.     } else if((*add)->hash>hash) {
  257.       /* continue search for a place to insert */
  258.       /* 'add' now points to the pointer */
  259.       prev=(*add);
  260.       add=(struct Identifier **)&((*add)->next);
  261.     } else {
  262.       /* insert it here! */
  263.       prev=(*add)->prev;
  264.       break;
  265.     }
  266.   }
  267.  
  268.   next=(*add);
  269.   *add=ident;
  270.   (*add)->hash=hash;
  271.   (*add)->prev=prev;
  272.   (*add)->next=next;
  273.   if(next)
  274.     next->prev=ident;
  275.   return(FPL_OK);
  276. }
  277.  
  278. /**********************************************************************
  279.  *
  280.  * int GetIdentifier();
  281.  *
  282.  * Sets the pointer to the Identifier structure to which the name
  283.  * fits, in the third argument.
  284.  *
  285.  *****/
  286.  
  287. #ifdef DEBUG
  288. int hashed=0;
  289. int max_hashed=0;
  290. #endif
  291.  
  292. ReturnCode 
  293. GetIdentifier(struct Data *scr,
  294.               char *name,
  295.           struct Identifier **ident)
  296. {
  297. #ifdef HIJACK
  298.   ReturnCode ret;
  299. #endif
  300.   struct Identifier *get;
  301.   unsigned long hash=Gethash(name);
  302.   get=scr->hash[hash%scr->hash_size];
  303. #ifdef DEBUG
  304.   hashed=0;
  305. #endif
  306.   while(get) {
  307.     if(
  308.  
  309.        (get->hash==hash) && 
  310.        /* identical hash value! */
  311.  
  312.        !strcmp(get->name, name) &&
  313.        /* identical name! */
  314.  
  315.        (!get->level || (get->func==scr->func && get->level<=scr->varlevel)) &&
  316.        /* If not global, declared under the *same* function, in this or
  317.       a lower level! */
  318.  
  319.        (!get->file || !strcmp(get->file, scr->prog->name))
  320.        /* If not cross-file, the same file! */
  321.  
  322.        ) {
  323.  
  324.       /* this is it! */
  325.       *ident=get;
  326. #ifdef DEBUG
  327.       if(hashed>max_hashed)
  328.     max_hashed=hashed;
  329. #endif
  330. #ifdef HIJACK
  331.       if(get->flags&FPL_HIJACKED_VARIABLE) {
  332.     CALL(Hijack(scr, get));
  333.       }
  334. #endif
  335.       return(FPL_OK);
  336.     } else if(get->hash<hash)
  337.       /* we've been searching through all possible alternatives! */
  338.       break;
  339. #ifdef DEBUG
  340.     hashed++;
  341. #endif
  342.     get=get->next;
  343.   }    
  344.   *ident=NULL;
  345.   return(FPLERR_IDENTIFIER_NOT_FOUND);
  346. }
  347.  
  348. #ifdef HIJACK
  349. /**********************************************************************
  350.  *
  351.  * fplHijack()
  352.  *
  353.  * This function makes the user able to hang on to a single non-array variable
  354.  * and to effect its contents. Whenever a "hijacked" variable is accessed or
  355.  * changed, the user will have a chance to confirm it or change the contents.
  356.  *
  357.  *****/
  358.  
  359. ReturnCode PREFIX fplHijack(AREG(0) struct Data *scr,
  360.                 AREG(1) char *name)
  361. {
  362.   ReturnCode ret;
  363.   struct Identifier *ident;
  364.   if(!scr && !name)
  365.     return(FPLERR_ILLEGAL_ANCHOR);
  366.   CALL(GetIdentifier(scr, name, &ident));
  367.   if(ident->data.variable.num ||   /* array */
  368.      !(ident->flags&FPL_VARIABLE)) /* no variable */
  369.     return(FPLERR_IDENTIFIER_NOT_FOUND);
  370.   ident->flags|=FPL_HIJACKED_VARIABLE;
  371.   return(FPL_OK);
  372. }
  373.  
  374. /*************************************************************************
  375.  *
  376.  * Hijack();
  377.  *
  378.  * This function gets called whenever a hijacked symbol has been selected
  379.  * by GetIdentifier().
  380.  *
  381.  ******/
  382.  
  383. static ReturnCode INLINE Hijack(struct Data *scr, struct Identifier *ident)
  384. {
  385.   struct fplArgument pass;
  386.   struct fplMsg *msg;
  387.   ReturnCode ret;
  388.   pass.argc=0;
  389.   pass.name=ident->name;
  390.   pass.ID=FPL_HIJACK_READ;
  391.   pass.key=scr;
  392.   CALL(InterfaceCall(scr, &pass, scr->function));
  393.   if(ident->flags&FPL_INT_VARIABLE) {
  394.     /*
  395.      * Integer variable hijack!
  396.      */
  397.     CALL(GetMessage(scr, FPLMSG_RETURN_INT, &msg));
  398.     if(msg) {
  399.       *ident->data.variable.var.val32=(long)msg->message[0];
  400.       CALL(DeleteMessage(scr, msg));
  401.     }
  402.   } else {
  403.     /*
  404.      * String variable hijack!
  405.      */
  406.     CALL(GetMessage(scr, FPLMSG_RETURN_STRING, &msg));
  407.     if(msg) {
  408.       if(ident->data.variable.var.str[0])
  409.     FREE(ident->data.variable.var.str[0]);
  410.       ident->data.variable.var.str[0]=(struct fplStr *)msg->message[0];
  411.       DeleteMessage(scr, msg);
  412.     }
  413.   }
  414.   return(FPL_OK);
  415. }
  416. #endif
  417.  
  418. /**********************************************************************
  419.  *
  420.  * int InitHash()
  421.  *
  422.  * Initialize the hash table. Simple and quick!
  423.  *
  424.  *****/
  425.  
  426. struct ShitData {
  427.   char *name;
  428.   long ID;
  429.   char ret;
  430.   char *format;
  431. };
  432.  
  433. struct MoreShitData {
  434.   char *name;
  435.   long ID;
  436.   long flags;
  437. };
  438.  
  439. static ReturnCode INLINE InitHash(struct Data *scr)
  440. {
  441.   ReturnCode ret;
  442.   static struct ShitData internal_functions[]={
  443. #ifdef AMIGA
  444.     {"openlib",        FNC_OPENLIB,    'I', "SI"},
  445.     {"closelib",    FNC_CLOSELIB,    'I', "S"},
  446. #endif
  447.     {"abs",        FNC_ABS,    'I', "I"},
  448.     {"atoi",        FNC_ATOI,    'I', "S"},
  449.     {"eval",        FNC_EVAL,    'I', "S"},
  450.     {"interpret",    FNC_INTERPRET,    'I', "S"},
  451.     {"itoa",        FNC_ITOA,    'S', "I"},
  452.     {"itoc",        FNC_ITOC,    'S', "I"},
  453.     {"joinstr",        FNC_JOINSTR,    'S', "s>"},
  454.     {"ltostr",        FNC_LTOSTR,    'S', "Ii"},
  455.     {"strcmp",        FNC_STRCMP,    'I', "SS"},
  456.     {"strlen",        FNC_STRLEN,    'I', "S"},
  457.     {"strncmp",        FNC_STRNCMP,    'I', "SSI"},
  458.     {"strstr",        FNC_STRSTR,    'I', "SS"},
  459.     {"strtol",        FNC_STRTOL,    'I', "Si"},
  460.     {"substr",        FNC_SUBSTR,    'S', "SII"},
  461.   };
  462.  
  463. /* FPL keywords. "else" is not included (treated special). */
  464.  
  465.   static struct MoreShitData keywords[]={
  466.     {"auto",    CMD_AUTO,    FPL_KEYWORD_DECLARE},
  467.     {"break",    CMD_BREAK,    0},
  468.     {"case",    CMD_CASE,    0},
  469.     {"char",    CMD_INT,    FPL_KEYWORD_DECLARE|FPL_CHAR_VARIABLE},
  470.     {"const",    CMD_CONST,    FPL_KEYWORD_DECLARE},
  471.     {"continue", CMD_CONTINUE,    0},
  472.     {"default",    CMD_DEFAULT,    0},
  473.     {"do",    CMD_DO,        0},
  474.     {"double",    CMD_DOUBLE,    FPL_IGNORE},
  475.     {"enum",    CMD_ENUM,    FPL_IGNORE},
  476.     {"exit",    CMD_EXIT,    0},
  477.     {"export",    CMD_EXPORT,    FPL_KEYWORD_DECLARE},
  478.     {"float",   CMD_FLOAT,    FPL_IGNORE},
  479.     {"for",    CMD_FOR,    0},
  480.     {"if",    CMD_IF,        0},
  481.     {"int",    CMD_INT,    FPL_KEYWORD_DECLARE},
  482.     {"long",    CMD_INT,    FPL_KEYWORD_DECLARE},
  483.     {"register",CMD_REGISTER,    FPL_KEYWORD_DECLARE},
  484.     {"resize",    CMD_RESIZE,    0},
  485.     {"return",    CMD_RETURN,    0},
  486.     {"short",    CMD_INT,    FPL_KEYWORD_DECLARE|FPL_SHORT_VARIABLE},
  487.     {"signed",    CMD_SIGNED,    FPL_KEYWORD_DECLARE|FPL_IGNORE},
  488.     {"static",  CMD_STATIC,    FPL_KEYWORD_DECLARE},
  489.     {"string",    CMD_STRING,    FPL_KEYWORD_DECLARE},
  490.     {"struct",  CMD_STRUCT,    FPL_IGNORE},
  491.     {"switch",    CMD_SWITCH,    0},
  492.     {"typedef",    CMD_TYPEDEF,    0},
  493.     {"union",    CMD_UNION,    FPL_IGNORE},
  494.     {"unsigned",CMD_UNSIGNED,    FPL_KEYWORD_DECLARE|FPL_IGNORE},
  495.     {"void",    CMD_VOID,    FPL_KEYWORD_DECLARE},
  496.     {"volatile",CMD_VOLATILE,    FPL_KEYWORD_DECLARE|FPL_IGNORE},
  497.     {"while",    CMD_WHILE,    0},
  498.   };
  499.   long i;
  500.   struct Identifier *ident;
  501.   GETMEMA(scr->hash, sizeof(struct Identifier *)* scr->hash_size);
  502.  
  503.   memset((void *)scr->hash, 0, sizeof(struct Identifier *)*scr->hash_size);
  504.   /*
  505.    * The hash table initialization gives us a brilliant chance to bring up
  506.    * the execution speed even more by inserting the few internal functions
  507.    * into this same table. The functions will then act *EXACTLY* the same
  508.    * and we can shorten the code and much easier write internal functions
  509.    * that return strings...
  510.    */
  511.  
  512.   for(i=0; i<sizeof(internal_functions)/sizeof(struct ShitData);i++) {
  513.     GETMEMA(ident, sizeof(struct Identifier));
  514.     ident->name=internal_functions[i].name;
  515.     ident->data.external.ID=internal_functions[i].ID;
  516.     ident->data.external.ret=internal_functions[i].ret;
  517.     ident->data.external.format=internal_functions[i].format;
  518.     ident->flags=FPL_INTERNAL_FUNCTION;
  519.     ident->level=0;
  520.     ident->func=NULL; /* all functions */
  521.     ident->file=NULL; /* everywhere */
  522.     ret=AddIdentifier(scr, ident);
  523.     if(ret)
  524.       break;
  525.   }
  526.   for(i=0; i<sizeof(keywords)/sizeof(struct MoreShitData);i++) {
  527.     GETMEMA(ident, sizeof(struct Identifier));
  528.     ident->name=keywords[i].name;
  529.     ident->data.external.ID=keywords[i].ID;  /* dirty enum work! */
  530.     ident->flags=FPL_KEYWORD|FPL_INTERNAL_FUNCTION|keywords[i].flags;
  531.     ident->level=0;
  532.     ident->func=NULL;  /* all functions */
  533.     ident->file=NULL;  /* everywhere */
  534.     ret=AddIdentifier(scr, ident);
  535.     if(ret)
  536.       break;
  537.   }
  538.   return(ret);
  539. }
  540.  
  541. /**********************************************************************
  542.  *
  543.  * int Gethash();
  544.  *
  545.  * Return the hash number for the name received as argument.
  546.  *
  547.  *****/
  548.  
  549. static unsigned long INLINE Gethash(char *name)
  550. {
  551.   unsigned long hash=0;
  552.   while(*name)
  553.     hash=(hash<<1)+*name+++(hash&(1<<31)?-2000000000:0);
  554.   return(hash);
  555. }
  556.  
  557. /**********************************************************************
  558.  *
  559.  * void Free();
  560.  *
  561.  * This function frees the resources used by this FPL session.
  562.  *
  563.  ***********/
  564.  
  565. void PREFIX fplFree(AREG(0) struct Data *scr)
  566. {
  567.   struct Data onstack;
  568.   long retval;
  569.   onstack=*scr; /* copy the entire struct */
  570.   scr=&onstack; /* use the `stack-struct' */
  571.   DelProgram(scr, NULL); /* remove all programs from memory, some might be
  572.                 Lock()'ed! */
  573.   CloseLib(scr, NULL, TRUE, &retval); /* force close of all funclibs */
  574.   FREEALL();
  575.   FREEALLA();
  576. }
  577.  
  578. /**********************************************************************
  579.  *
  580.  * int DelIdentifier()
  581.  *
  582.  * Delete an identifier from the hash table. Specify 'name' or 'ident'.
  583.  *
  584.  ******/
  585.  
  586. ReturnCode 
  587. DelIdentifier(struct Data *scr,
  588.               char *name,
  589.           struct Identifier *ident)
  590. {
  591.   ReturnCode ret;
  592.   long i;
  593.   struct fplVariable *var;
  594.  
  595.   if(!ident) {
  596.     /* Get the structure pointer */
  597.     CALL(GetIdentifier(scr, name, &ident));
  598.   }
  599.   
  600.   /* Link the previous member in the list to the next member */
  601.   if(ident->prev)
  602.     /* If there is a previous member */
  603.     ident->prev->next=ident->next;
  604.   else
  605.     /* if this was the first in the list */
  606.     scr->hash[ident->hash%scr->hash_size]=ident->next;
  607.  
  608.   if(ident->next)
  609.     ident->next->prev=ident->prev;
  610.  
  611.   /*
  612.    * If it is any kind of funtion, all the data the pointers points to
  613.    * should (in the specs) be static and should therefore *NOT* be
  614.    * freed here!
  615.    *
  616.    * Notice that even internal functions are possible to remove here...
  617.    */
  618.  
  619.   if(ident->flags&FPL_VARIABLE) {
  620.     /*
  621.      * It's a variable identifier. Free some members:
  622.      */
  623.     
  624.     var=&ident->data.variable;
  625.     
  626.     if(ident->flags&FPL_COPIED_DATA)
  627.       *ident->data.variable.temp= ident->data.variable; /* copyback */
  628.     else {
  629.       if(ident->flags&FPL_STRING_VARIABLE) {
  630.     /* it's a string array! */
  631.     for(i=0; i<var->size; i++)
  632.       if(var->var.str[i]) {
  633.         FREE(var->var.str[i]);
  634.       }
  635.       }
  636.       if(var->num)
  637.     FREE(var->dims);
  638.       FREE(var->var.val);
  639.     }
  640.   } else if(ident->flags&FPL_INSIDE_FUNCTION)
  641.     FREE(ident->data.inside.format);
  642.  
  643.   if((ident->flags&FPL_EXTERNAL_FUNCTION)||
  644.      (ident->flags&FPL_INTERNAL_FUNCTION)) {
  645.     /* internal or external function */
  646.     FREEA(ident);
  647.   } else  {
  648.     FREE(ident->name); /* only if dynamically allocated! */
  649.     FREE(ident);
  650.   }
  651.   return(ret);
  652. }
  653.  
  654. /**********************************************************************
  655.  *
  656.  * fplInit();
  657.  *
  658.  * Initialize a lot of FPL internal structures and references. Returns
  659.  * NULL if anything went wrong!
  660.  *
  661.  *******/
  662.  
  663. void * ASM fplInit(AREG(0) long (*function) (void *),
  664.            /* function handler pointer */
  665.            AREG(1) unsigned long *tags) /* taglist */
  666. {
  667.   struct Data point;
  668.   struct Data *scr;
  669.   void *init;
  670.   scr=&point;
  671.  
  672. #ifdef AMIGA
  673.   /* Store all register before loading index register */
  674.   StoreRegisters(scr);
  675.   geta4();
  676. #endif
  677.  
  678.   init=Init(&point, function, tags);
  679.   if(!init)
  680.     FREEALLA();
  681.   return(init);
  682. }
  683.  
  684. static void * INLINE Init(struct Data *scr,    /* stack oriented */
  685.               long ASM (*function) (AREG(0) void *), 
  686.               unsigned long *tags) /* taglist */
  687. {
  688.   ReturnCode ret;
  689.   char *buffer;
  690.   struct Data *ptr;
  691. #ifdef AMIGA
  692.   long registers[11];
  693.  
  694.   memcpy(registers, scr->registers, sizeof(long)*11);
  695. #endif
  696.   /* Set default that just might get changed in SetTags(); */
  697.  
  698.   memset(scr, 0, sizeof(struct Data)); /* NULLs everything! */
  699.  
  700.   scr->Alloc=DefaultAlloc;
  701.   scr->Dealloc=DefaultDealloc;;
  702.   scr->hash_size=FPL_HASH_SIZE;
  703.   scr->runs=0;
  704.   InitFree(scr); /* init memory caches */
  705.  
  706. #ifdef AMIGA
  707.  
  708.   memcpy(scr->registers, registers, sizeof(long)*11);
  709.  
  710.   scr->stack_size=FPL_MIN_STACK;
  711.   scr->stack_max=FPL_MAX_STACK;
  712.   scr->stack_limit=FPL_MAX_LIMIT;
  713.   scr->stack_margin=FPLSTACK_MINIMUM;
  714. #endif
  715.  
  716.   SetTags(scr, tags); /* read tags and set proper members */
  717.  
  718.   buffer=(char *)MALLOCA(BUF_SIZE);
  719.   if(!buffer)
  720.     /* fail! */
  721.     return(NULL);
  722.  
  723. #ifdef AMIGA
  724. #pragma msg 225 ignore    /* ignore the 225 warnings that occur on the following
  725.                assign! */
  726. #endif
  727.   scr->function=(long ASM (*)(AREG(0) void *))function;
  728.  
  729. #ifdef AMIGA
  730. #pragma msg 225 warning    /* enable the 225 warnings again! */
  731. #endif
  732.  
  733.   scr->buf=buffer;
  734.  
  735. #if defined(AMIGA) && defined(SHARED)
  736.   scr->stack_base=MALLOCA(scr->stack_size);
  737.   if(!scr->stack_base)
  738.     return(NULL);
  739.   *(int *)scr->stack_base=scr->stack_size; /* size of stack in the first
  740.                           four bytes! */
  741. #endif
  742.  
  743.   if(ret=InitHash(scr))
  744.     return(NULL);
  745.  
  746.   ptr=(struct Data *)MALLOCA(sizeof(struct Data));
  747.   if(ptr)
  748.     *ptr=*scr; /* copy the entire structure! */
  749.  
  750.   return((void *)ptr);
  751. }
  752.  
  753. /**********************************************************************
  754.  *
  755.  * fplReset();
  756.  *
  757.  * This function is used to change or add tags to FPL. All tags
  758.  * available for fplFree() is legal. Not changed tags will remain
  759.  * as they were before this call!
  760.  *
  761.  * I had to insert this function since I found out that I wanted to
  762.  * alter the userdata in my application using FPL, and that was hard
  763.  * doing so (nice) without this change.
  764.  * 
  765.  * Library front end to SetTags();
  766.  *
  767.  *****/
  768.  
  769. ReturnCode PREFIX fplReset(AREG(0) struct Data *scr,
  770.                 AREG(1) unsigned long *tags)
  771. {
  772.   ReturnCode ret;
  773.   if(!scr)
  774.     ret=FPLERR_ILLEGAL_ANCHOR;
  775.   else
  776.     ret=SetTags(scr, tags);
  777.   return(ret);
  778. }
  779.  
  780.  
  781. /**********************************************************************
  782.  *
  783.  * SetTags();
  784.  *
  785.  * Read the taglist supplied in the second parameter, and set all data
  786.  * according to those.
  787.  *
  788.  *****/
  789.  
  790. static ReturnCode 
  791. SetTags(struct Data *scr,
  792.         unsigned long *tags)
  793. {
  794.   if(!scr)
  795.     return(FPLERR_ILLEGAL_ANCHOR);
  796.  
  797.   while(tags && *tags) {
  798.     switch(*tags++) {
  799. #ifdef AMIGA
  800. #pragma msg 225 ignore    /* ignore the 225 warnings that occur on the following
  801.                four assigns! */
  802. #endif
  803.     case FPLTAG_INTERVAL:
  804.       scr->interfunc=(long ASM (*)(AREG(0) void *))*tags;
  805.       break;
  806.     case FPLTAG_NEWLINE_HOOK:
  807.       scr->newline_hook=(long ASM (*)(AREG(0) void *))*tags;
  808.       break;
  809.     case FPLTAG_INTERNAL_ALLOC:
  810.       scr->Alloc=(void * ASM (*)(DREG(0) long))*tags;
  811.       break;
  812.     case FPLTAG_INTERNAL_DEALLOC:
  813.       scr->Dealloc=(void ASM (*)(AREG(1) void *, DREG(0) long))*tags;
  814.       break;
  815. #ifdef AMIGA
  816. #pragma msg 225 warning /* enable the 225 warning again for correct program
  817.                checking! */
  818. #endif
  819.  
  820.     case FPLTAG_HASH_TABLE_SIZE:
  821.       if(*tags>FPL_MIN_HASH)
  822.     scr->hash_size=*tags;
  823.       break;
  824.     case FPLTAG_USERDATA:
  825.       scr->userdata=(void *)*tags;
  826.       break;
  827.     case FPLTAG_ALLFUNCTIONS:
  828.       if(*tags)
  829.     scr->flags|=FPLDATA_ALLFUNCTIONS;
  830.       else
  831.     scr->flags&=~FPLDATA_ALLFUNCTIONS;
  832.       break;
  833.     case FPLTAG_NESTED_COMMENTS:
  834.       if(*tags)
  835.     scr->flags|=FPLDATA_NESTED_COMMENTS;
  836.       else
  837.     scr->flags&=~FPLDATA_NESTED_COMMENTS;
  838.       break;
  839.     case FPLTAG_CACHEALLFILES:
  840.       if(*tags) {
  841.     scr->flags|=FPLDATA_CACHEALLFILES;
  842.     if(*tags == FPLCACHE_EXPORTS)
  843.       scr->flags|=FPLDATA_CACHEEXPORTS;
  844.       } else
  845.     scr->flags&=~FPLDATA_CACHEALLFILES;
  846.       break;
  847. #ifdef STRING_STACK
  848.     case FPLTAG_STRINGSTACK:
  849.       scr->strings_in_stack_max = (long)*tags;
  850.       if( scr->strings_in_stack_max>0 ) {
  851.         if(scr->stringsstack) {
  852.           FREEA(scr->stringsstack);
  853.         }
  854.         GETMEMA(scr->stringstack, scr->strings_in_stack_max *
  855.                                   sizeof( struct StringStack ));
  856.       }
  857.       break;
  858. #endif
  859.  
  860. #ifdef AMIGA
  861.     case FPLTAG_STACK:
  862.       /* Only change stack if the required size is large enough! */
  863.       if(*tags>FPL_MIN_STACK)
  864.     scr->stack_size=(long)*tags;
  865.       break;
  866.     case FPLTAG_MAXSTACK:
  867.       /* Only change this if the required size is large enough! */
  868.       if(*tags>FPL_MIN_STACK)
  869.     scr->stack_max=(long)*tags;
  870.       break;
  871.     case FPLTAG_STACKLIMIT:
  872.       /* Only change this if the required size is large enough! */
  873.       if(*tags>FPL_MIN_STACK)
  874.     scr->stack_limit=(long)*tags;      
  875.       break;
  876.     case FPLTAG_MINSTACK:
  877.       /* Only change this if the required size is larger than default! */
  878.       if(*tags>FPLSTACK_MINIMUM)
  879.     scr->stack_margin=*tags;
  880.       break;
  881.     case FPLTAG_LOCKUSED:
  882.       /* This determines whether to use locked files when executing or not.
  883.      Default is false. */
  884.       if(*tags)
  885.     scr->flags|=FPLDATA_LOCKUSED;
  886.       else
  887.     scr->flags&=~FPLDATA_LOCKUSED;
  888.       break;
  889. #endif
  890.     }
  891.     tags++; /* next! */
  892.   }
  893.   return(FPL_OK);
  894. }
  895.